using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net;
using System.Threading;
using Microsoft.WindowsAzure;
using Microsoft.WindowsAzure.Diagnostics;
using Microsoft.WindowsAzure.ServiceRuntime;
using Microsoft.WindowsAzure.Storage;
using System.Net.Sockets;
using System.Text;

namespace Tower
{
    public class WorkerRole : RoleEntryPoint
    {
        private class TowerListener : TcpListener
        {
            private static TowerListener _instance = null;

            private TowerListener(IPAddress iPAddress, int INCOMING_PORT) 
                : base(iPAddress, INCOMING_PORT)
            {
                Debug.Print("Creating new instance");
            }

            public bool IsListening
            {
                get
                {
                    return this.Active;
                }
            }

            public static TowerListener GetServer()
            {
                if (_instance == null)
                    _instance = new TowerListener(IPAddress.Loopback, INCOMING_PORT);

                return _instance;
            }
        }

        private static int INCOMING_PORT = 51246;

        private TowerListener server { get; set; }

        public override void Run()
        {
            // This is a sample worker implementation. Replace with your logic.
            Trace.TraceInformation("Tower entry point called", "Information");

            byte[] buff = new byte[255];
            NetworkStream stream;
            TcpClient client;

            String input = null;

            while (true)
            {
                Console.WriteLine("Waiting for connection...");

                client = server.AcceptTcpClient();
                if (!client.Connected)
                    return;

                Console.WriteLine("Connected!");
                input = null;

                stream = client.GetStream();

                String cmd = null;

                Send("CONNECTED", stream);

                int count;
                while (( count = (stream.Read(buff, 0, buff.Length))) != 0)
                {
                    input = System.Text.Encoding.ASCII.GetString(buff, 0, count);

                    if (input != Environment.NewLine)
                        cmd = cmd + input;
                    else if(cmd != null)
                    {
                        Console.WriteLine(String.Format("Received: {0}", cmd));
                        this.ProcessCommand(cmd, stream);
                        cmd = null;
                    }
                }
            }
        }

        private void ProcessCommand(string cmd, NetworkStream stream)
        {
            switch (cmd)
            {
                case "CLOSE":
                    break;
                case "REGISTER":
                    {
                        var chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz";
                        var random = new Random();
                        var result = new string(
                            Enumerable.Repeat(chars, 8)
                                      .Select(s => s[random.Next(s.Length)])
                                      .ToArray());

                        StringBuilder sb = new StringBuilder(Guid.NewGuid().ToString());
                        sb.Append(";");
                        sb.Append(result);

                        Send(sb.ToString(), stream);
                        break;
                    }
                case "UPLOAD":
                    break;
                default:
                    break;
            }
        }

        private void Send(string message, NetworkStream stream)
        {
            byte[] bytes = System.Text.Encoding.ASCII.GetBytes(message + Environment.NewLine);

            stream.Write(bytes, 0, bytes.Length);
            Console.WriteLine(String.Format("Sent: {0}", message));
        }

        public override bool OnStart()
        {
            // Set the maximum number of concurrent connections 
            ServicePointManager.DefaultConnectionLimit = 12;

            // For information on handling configuration changes
            // see the MSDN topic at http://go.microsoft.com/fwlink/?LinkId=166357.

            try
            {
                if (server == null)
                    server = TowerListener.GetServer();

                if (!server.IsListening)
                    server.Start();
            }
            catch (Exception)
            {

            }

            Trace.TraceInformation("Tower listening service has started on port {0}", INCOMING_PORT);

            return base.OnStart();
        }

        public override void OnStop()
        {
            server.Stop();

            base.OnStop();
        }
    }
}
